/*
	PacoBlaze test
*/

`define PACOBLAZE3M
`define HAS_DEBUG

`define TEST_FILE1 "/home/eitan/Documents/VLSI/hw2/SW/matrixDuo.rmh"
`define TEST_FILE2 "/home/eitan/Documents/VLSI/hw2/SW/matrix2.rmh"
`define RAM_FILE  "/home/eitan/Documents/VLSI/hw2/SW/matrix.ram"
`define REG_FILE1 "/home/eitan/Documents/VLSI/hw2/SW/reg1_2.ram"
`define REG_FILE2 "/home/eitan/Documents/VLSI/hw2/SW/reg2_2.ram"

`include "timescale_inc.v"
`include "pacoblaze_inc.v"

`define SIM

module pacoblaze3m_tb;

parameter tck = 10, program_cycles = 102400;

//reg clk, 
/*input clk;
input in;
output out;*/

reg clk;
reg rst, ir; // clock, reset, interrupt request
wire [`operand_width-1:0] pa, po; // port id, port output

wire [`code_depth-1:0] ad1; // instruction address
wire rd1, wr1; // read strobe, write strobe
wire [`code_width-1:0] di1; // program data input

wire [`code_depth-1:0] ad2; // instruction address
wire rd2, wr2; // read strobe, write strobe
wire [`code_width-1:0] di2; // program data input

`ifdef HAS_INTERRUPT_ACK
wire ia; // interrupt acknowledge
`endif

reg [`operand_width-1:0] prt[0:`port_size-1]; // port memory


wire [`operand_width-1:0] pi = prt[pa]; // port input
wire [`scratch_depth-1:0] ram_address1;
wire [`scratch_width-1:0] ram_write1;
wire [`scratch_width-1:0] ram_read1;
wire ram_write_en1;
wire ram_en1;

wire [`scratch_depth-1:0] ram_address2;
wire [`scratch_width-1:0] ram_write2;
wire [`scratch_width-1:0] ram_read2;
wire ram_write_en2;
wire ram_en2;
 
/* PacoBlaze program memory (1) */
blockram #(.width(`code_width), .depth(`code_depth))
	rom1(
	.clk(clk),
	.rst(rst),
	.enb(1'b1),
	.wen(1'b0),
	.addr(ad1),
	.din(`code_width 'b0),
	.dout(di1)
);


/* PacoBlaze program memory (2) */
blockram #(.width(`code_width), .depth(`code_depth))
	rom2(
	.clk(clk),
	.rst(rst),
	.enb(1'b1),
	.wen(1'b0),
	.addr(ad2),
	.din(`code_width 'b0),
	.dout(di2)
);


/* PacoBlaze ram */
/*
memory_scratch scratch(
	.address1(ram_address1),
	.write_enable1(ram_write_en1), 
	.data_in1(ram_write1), 
	.data_out1(ram_read1),
	.address2(ram_address2),
	.write_enable2(ram_write_en2), 
	.data_in2(ram_write2), 
	.data_out2(ram_read2),
	.reset(1'b0),
	.clk(clk)
);
*/

blockramDuo #(.width(`scratch_width), .depth(`scratch_depth))
scratch(
	.clk(clk), 
	.rst(1'b0), 
	.enb1(1'b1), 
	.wen1(ram_write_en1), 
	.addr1(ram_address1), 
	.din1(ram_write1), 
	.dout1(ram_read1),
	.enb2(1'b1), 
	.wen2(ram_write_en2), 
	.addr2(ram_address2), 
	.din2(ram_write2), 
	.dout2(ram_read2)
);
 

/* PacoBlaze dut */
pacoblaze3m dut(
	.clk(clk),
	.reset(rst),
	.address(ad1),
	.instruction(di1),
	.ram_address(ram_address1), 
	.ram_write(ram_write1), 
	.ram_read(ram_read1), 
	.ram_write_en(ram_write_en1), 
	.ram_en(ram_en1),
	.port_id(pa),
	.read_strobe(rd1),
	.write_strobe(wr1),
	.in_port(pi),
	.out_port(po),
	.interrupt(ir)
`ifdef HAS_INTERRUPT_ACK
	,	.interrupt_ack(ia)
`endif
);


pacoblaze3m dut2(
	.clk(clk),
	.reset(rst),
	.address(ad2),
	.instruction(di2),
	.ram_address(ram_address2), 
	.ram_write(ram_write2), 
	.ram_read(ram_read2), 
	.ram_write_en(ram_write_en2), 
	.ram_en(ram_en2),
	.port_id(pa),
	.read_strobe(rd2),
	.write_strobe(wr2),
	.in_port(pi),
	.out_port(po),
	.interrupt(ir)
`ifdef HAS_INTERRUPT_ACK
	,	.interrupt_ack(ia)
`endif
);

`ifdef SIM
/* Clocking device */
always #(tck/2) clk = ~clk;

/* Watch port memory */
always @(posedge clk)	if (wr1) prt[pa] <= po;

/* Simulation setup */
initial begin
	$dumpvars(0, dut);
	$dumpfile("pacoblaze3m_tb.vcd");
	$readmemh(`TEST_FILE1, rom1.ram);
	$readmemh(`TEST_FILE1, rom2.ram);
	$readmemh(`REG_FILE1, dut.register.dpre);
	$readmemh(`REG_FILE2, dut2.register.dpre);
	$readmemh(`RAM_FILE,  scratch.ram);
`ifdef HAS_DEBUG
	$monitor("%s,\t odd regs: %x \t even regs: %x\n Ram: %x", 
		dut.idu_debug, 
		dut.register.dpre,
		dut.register.dpro,
		scratch.ram);
//	$monitor("[scratch.shm.sh.in]%b \n %s ", scratch.shm.sh.in, 1'b1);
	
`endif
end 

/* Simulation */
integer i;
initial begin
	

	for (i=0; i<`port_size; i=i+1) prt[i] = i; // initialize ports
	clk = 0; rst = 1; ir = 0;
	#(tck*2);
	@(negedge clk) rst = 0; // free processor

//	#(tck*30);
//	@(negedge clk) ir = 1; // interrupt request
//	// @(negedge clk) ;
//	@(negedge clk) ir = 0;

	#(program_cycles*tck+100) begin
		$finish;
		end
end
`endif
endmodule
